#include <stdint.h>
#include "wm_internal_flash.h"
#include "wm_crypto_hard.h"
#include "wm_uart.h"
#include "fifo.h"

#define TX_TIMEOUT 1000
#define LEN 4096
static uint8_t buf[32]; // 必须大于等于32字节
static uint8_t pdata[LEN];

struct
{
	int size;
	int protocol;
	int index;
	int curPackNO;	
	char buff[1024+5];
}xmodeData;

static UART_HandleTypeDef huart0;

#define XMODEM          0x01
#define XMODEM1K      0x02

#define SOH		0x1
#define STX		0x2
#define EOT		0x4
#define ACK		0x6
#define NAK		0x15
#define CANCEL	0x18

struct
{
	int size;
    int curAddr;
}flashData;

__attribute__((isr)) void UART0_IRQHandler(void)
{
	HAL_UART_IRQHandler(&huart0);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	FifoWrite(huart->pRxBuffPtr, huart->RxXferCount);
}

void xmodem_download(void)
{
	// int i;
	int step = 0;

	// char buff[128];
	int recsize;
	// int wrtsize;
	uint8_t respon[1];

	uint32_t crcInt = 0;
	unsigned short crcWord;	
	CRC_HandleTypeDef crcContext;

	printf("Entry xmodem transmission ...\n");
    printf("Switching baud rate to 2000000 ...\n");
	
	FifoInit(pdata, LEN);
	__HAL_RCC_UART0_CLK_ENABLE();
	__HAL_RCC_GPIO_CLK_ENABLE();
	
	HAL_NVIC_SetPriority(UART0_IRQn, 0);
	HAL_NVIC_EnableIRQ(UART0_IRQn);

	huart0.Instance = UART0;
	huart0.Init.BaudRate = 2000000;
	huart0.Init.WordLength = UART_WORDLENGTH_8B;
	huart0.Init.StopBits = UART_STOPBITS_1;
	huart0.Init.Parity = UART_PARITY_NONE;
	huart0.Init.Mode = UART_MODE_TX | UART_MODE_RX;
	huart0.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	HAL_UART_Init(&huart0);
	
	HAL_UART_Receive_IT(&huart0, buf, 0);

	xmodeData.size = 0;
	xmodeData.curPackNO = 1;

    flashData.size = 0;
    flashData.curAddr = 0x96000;

	while(1)
	{
        if(step == 1)
        {
            //printf("1111");			
            recsize = FifoRead((uint8_t *)xmodeData.buff+xmodeData.size, 128);
            xmodeData.size += recsize;
            if(recsize>0)
            {
                //printf("%d\n",recsize);
                //xmodeData.buff[recsize] = 0;
                //printf("%s",xmodeData.buff);
                step=2;
                flashData.size = 0;
                flashData.curAddr = 0;	
            }
        }
        switch(step)
        {
            case 0:
            case 1:	
                if(step == 0)
                {
                    xmodeData.size=0;
                    xmodeData.curPackNO = 1;
                }
                do
                {
                    recsize = FifoRead((uint8_t *)xmodeData.buff+xmodeData.size, 128);
                    if(recsize == 0)
                    {
                        HAL_Delay(2); 
                    }
                    recsize = FifoRead((uint8_t *)xmodeData.buff+xmodeData.size, 128);
                }while(recsize);
				respon[0] = 'C';
                HAL_UART_Transmit(&huart0, &respon[0], 1, TX_TIMEOUT);
                HAL_Delay(600);
                step = 1;
            break;
            case 2:
                recsize = FifoRead((uint8_t *)xmodeData.buff+xmodeData.size, 128); 
                xmodeData.size += recsize;
                if(recsize>0)
                {
                    //printf("%d\n",recsize);
                    //buff[recsize] = 0;
                    //printf("%s",buff);
                }
                else
                {
                    //if(xmodeData.size>)
                    {
                            
                    }
                }
                if((xmodeData.size == 1) && (xmodeData.buff[0] == EOT))
                {
                    respon[0] = ACK;
                    HAL_UART_Transmit(&huart0, &respon[0], 1, TX_TIMEOUT);
                    //printf("4444");
                    step = 0;
                    xmodeData.size=0;
                    HAL_Delay(400);
                    // printf("finish,OK\n");
                    break;	
                }
                if(xmodeData.size>3)
                {
                    xmodeData.protocol=xmodeData.buff[0];
                    xmodeData.index = xmodeData.buff[1];
                    if((255-xmodeData.index) != xmodeData.buff[2])
                    {
                        // printf("2222");			
                        step = 0;
                        xmodeData.size=0;
                    
                        break;
                    }
                    if(xmodeData.index != xmodeData.curPackNO)
                    {
                        if(xmodeData.index == xmodeData.curPackNO-1)
                        {
                            
                        }
                        
                        // printf("3333");
                        step = 0;
                        xmodeData.size=0;
                        break;						
                    }
                    if(xmodeData.protocol == XMODEM)
                    {
                        if(xmodeData.size == 128+5)
                        {
                            /* Calculate the current frame's CRC and copy the firmware data to the load_address. */
							HAL_CRYPTO_CRC_Init(&crcContext, 0, CRYPTO_CRC_TYPE_16_CCITT, 0);
							HAL_CRYPTO_CRC_Update(&crcContext, (uint8_t *)&(xmodeData.buff[3]), 128);
							HAL_CRYPTO_CRC_Final(&crcContext, &crcInt);

                            crcWord = (xmodeData.buff[128+5-2]<<8)+xmodeData.buff[128+5-1];

                            if(crcInt == crcWord)/* Check the current frame's CRC. */
                            {
                                respon[0] = ACK;	
                                xmodeData.curPackNO++;
                                if(xmodeData.curPackNO == 256)
                                {
                                    xmodeData.curPackNO=0;
                                }

                                HAL_FLASH_Write(flashData.curAddr,  (uint8_t *)&xmodeData.buff[3], 128);

                                flashData.size += 128;
                                flashData.curAddr += 128; 
                            }
                            else
                            {
                                respon[0] = NAK;
                            }
                            HAL_UART_Transmit(&huart0, &respon[0], 1, TX_TIMEOUT);
                            xmodeData.size=0;
                        }
                    }
                    else if(xmodeData.protocol == XMODEM1K)
                    {
                        if(xmodeData.size == 1024+5)
                        {
                            /* Calculate the current frame's CRC and copy the firmware data to the load_address. */
							HAL_CRYPTO_CRC_Init(&crcContext, 0, CRYPTO_CRC_TYPE_16_CCITT, 0);
							HAL_CRYPTO_CRC_Update(&crcContext, (uint8_t *)&(xmodeData.buff[3]), 1024);
							HAL_CRYPTO_CRC_Final(&crcContext, &crcInt);

                            crcWord = (xmodeData.buff[1024+5-2]<<8)+xmodeData.buff[1024+5-1];

                            if(crcInt == crcWord)/* Check the current frame's CRC. */
                            {
                                respon[0] = ACK;	
                                xmodeData.curPackNO++;
                                if(xmodeData.curPackNO == 256)
                                {
                                    xmodeData.curPackNO=0;
                                }
                                HAL_FLASH_Write(flashData.curAddr, (uint8_t *)&xmodeData.buff[3], 1024);
                                flashData.size += 1024;
                                flashData.curAddr += 1024;                               
                            }
                            else
                            {
                                respon[0] = NAK;
                            }
                            HAL_UART_Transmit(&huart0, &respon[0], 1, TX_TIMEOUT);
                            xmodeData.size=0;
                        }						
                    }
                }
                step =2;
                break;
        }
			// HAL_Delay(2);
	}
}

